#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Matplotlib 高级图表类型示例
演示复杂的可视化技术和高级图表类型
"""

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
import matplotlib.patches as patches

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

def contour_plots():
    """等高线图示例"""
    print("=== 等高线图示例 ===")
    
    # 创建网格数据
    x = np.linspace(-3, 3, 100)
    y = np.linspace(-3, 3, 100)
    X, Y = np.meshgrid(x, y)
    
    plt.figure(figsize=(15, 10))
    
    # 子图1: 基本等高线图
    plt.subplot(2, 3, 1)
    Z1 = np.sin(X) * np.cos(Y)
    contour = plt.contour(X, Y, Z1, levels=10, colors='black')
    plt.clabel(contour, inline=True, fontsize=8)
    plt.title('基本等高线图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图2: 填充等高线图
    plt.subplot(2, 3, 2)
    Z2 = X**2 + Y**2
    plt.contourf(X, Y, Z2, levels=20, cmap='viridis')
    plt.colorbar()
    plt.title('填充等高线图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图3: 组合等高线图
    plt.subplot(2, 3, 3)
    Z3 = np.exp(-(X**2 + Y**2))
    plt.contourf(X, Y, Z3, levels=15, cmap='coolwarm', alpha=0.8)
    contour = plt.contour(X, Y, Z3, levels=15, colors='black', linewidths=0.5)
    plt.clabel(contour, inline=True, fontsize=8)
    plt.colorbar()
    plt.title('组合等高线图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图4: 3D函数的等高线
    plt.subplot(2, 3, 4)
    Z4 = np.sin(np.sqrt(X**2 + Y**2))
    cs = plt.contourf(X, Y, Z4, levels=20, cmap='plasma')
    plt.colorbar(cs)
    plt.title('波纹函数等高线')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图5: 自定义等高线
    plt.subplot(2, 3, 5)
    Z5 = X*np.exp(-X**2 - Y**2)
    levels = np.linspace(Z5.min(), Z5.max(), 15)
    cs = plt.contourf(X, Y, Z5, levels=levels, cmap='RdYlBu')
    plt.colorbar(cs)
    plt.title('自定义等高线')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图6: 负值等高线
    plt.subplot(2, 3, 6)
    Z6 = np.sin(X) + np.cos(Y)
    cs = plt.contourf(X, Y, Z6, levels=np.linspace(-2, 2, 20), cmap='seismic')
    plt.colorbar(cs)
    plt.title('负值等高线')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    plt.tight_layout()
    plt.show()

def heatmap_examples():
    """热力图示例"""
    print("=== 热力图示例 ===")
    
    plt.figure(figsize=(15, 10))
    
    # 子图1: 基本热力图
    plt.subplot(2, 3, 1)
    data1 = np.random.randn(10, 10)
    im1 = plt.imshow(data1, cmap='hot', interpolation='nearest')
    plt.colorbar(im1)
    plt.title('基本热力图')
    
    # 子图2: 相关性矩阵热力图
    plt.subplot(2, 3, 2)
    # 生成相关性矩阵
    np.random.seed(42)
    data = np.random.randn(5, 100)
    corr_matrix = np.corrcoef(data)
    
    im2 = plt.imshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1)
    plt.colorbar(im2)
    plt.title('相关性矩阵')
    
    # 添加数值标签
    for i in range(len(corr_matrix)):
        for j in range(len(corr_matrix)):
            plt.text(j, i, f'{corr_matrix[i, j]:.2f}', 
                    ha='center', va='center', fontsize=8)
    
    # 子图3: 自定义colormap
    plt.subplot(2, 3, 3)
    colors = ['blue', 'white', 'red']
    n_bins = 100
    custom_cmap = LinearSegmentedColormap.from_list('custom', colors, N=n_bins)
    
    data3 = np.random.rand(15, 15) * 2 - 1  # -1到1的随机数
    im3 = plt.imshow(data3, cmap=custom_cmap)
    plt.colorbar(im3)
    plt.title('自定义颜色映射')
    
    # 子图4: 分类热力图
    plt.subplot(2, 3, 4)
    categories = ['类别A', '类别B', '类别C', '类别D']
    features = ['特征1', '特征2', '特征3', '特征4', '特征5']
    data4 = np.random.rand(len(categories), len(features))
    
    im4 = plt.imshow(data4, cmap='viridis')
    plt.colorbar(im4)
    plt.xticks(range(len(features)), features, rotation=45)
    plt.yticks(range(len(categories)), categories)
    plt.title('分类特征热力图')
    
    # 子图5: 时间序列热力图
    plt.subplot(2, 3, 5)
    days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    hours = range(24)
    data5 = np.random.rand(len(days), len(hours)) * 100
    
    im5 = plt.imshow(data5, cmap='YlOrRd', aspect='auto')
    plt.colorbar(im5, label='活动量')
    plt.xticks(range(0, 24, 4), [f'{h}:00' for h in range(0, 24, 4)])
    plt.yticks(range(len(days)), days)
    plt.title('一周活动热力图')
    plt.xlabel('时间')
    
    # 子图6: 距离矩阵热力图
    plt.subplot(2, 3, 6)
    cities = ['北京', '上海', '广州', '深圳', '杭州']
    n_cities = len(cities)
    
    # 生成模拟距离矩阵
    np.random.seed(123)
    distances = np.random.rand(n_cities, n_cities) * 1000
    # 使矩阵对称，对角线为0
    distances = (distances + distances.T) / 2
    np.fill_diagonal(distances, 0)
    
    im6 = plt.imshow(distances, cmap='Blues')
    plt.colorbar(im6, label='距离(km)')
    plt.xticks(range(n_cities), cities, rotation=45)
    plt.yticks(range(n_cities), cities)
    plt.title('城市距离矩阵')
    
    plt.tight_layout()
    plt.show()

def boxplot_violin_examples():
    """箱线图和小提琴图示例"""
    print("=== 箱线图和小提琴图示例 ===")
    
    # 生成测试数据
    np.random.seed(42)
    data1 = np.random.normal(0, 1, 100)
    data2 = np.random.normal(1, 1.5, 100)
    data3 = np.random.normal(-1, 0.5, 100)
    data4 = np.random.exponential(1, 100)
    
    data_list = [data1, data2, data3, data4]
    labels = ['正态1', '正态2', '正态3', '指数']
    
    plt.figure(figsize=(15, 10))
    
    # 子图1: 基本箱线图
    plt.subplot(2, 3, 1)
    plt.boxplot(data_list, labels=labels)
    plt.title('基本箱线图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图2: 水平箱线图
    plt.subplot(2, 3, 2)
    plt.boxplot(data_list, labels=labels, vert=False)
    plt.title('水平箱线图')
    plt.xlabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图3: 自定义箱线图
    plt.subplot(2, 3, 3)
    box_plot = plt.boxplot(data_list, labels=labels, patch_artist=True)
    colors = ['lightblue', 'lightgreen', 'lightcoral', 'lightyellow']
    for patch, color in zip(box_plot['boxes'], colors):
        patch.set_facecolor(color)
    plt.title('彩色箱线图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图4: 小提琴图
    plt.subplot(2, 3, 4)
    parts = plt.violinplot(data_list, positions=range(1, len(data_list)+1))
    plt.xticks(range(1, len(labels)+1), labels)
    plt.title('小提琴图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图5: 组合箱线图和小提琴图
    plt.subplot(2, 3, 5)
    plt.violinplot(data_list, positions=range(1, len(data_list)+1), alpha=0.7)
    plt.boxplot(data_list, positions=range(1, len(data_list)+1))
    plt.xticks(range(1, len(labels)+1), labels)
    plt.title('组合图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图6: 分组箱线图
    plt.subplot(2, 3, 6)
    group1 = [data1, data2]
    group2 = [data3, data4]
    
    positions1 = [1, 2]
    positions2 = [4, 5]
    
    bp1 = plt.boxplot(group1, positions=positions1, widths=0.6, patch_artist=True)
    bp2 = plt.boxplot(group2, positions=positions2, widths=0.6, patch_artist=True)
    
    for patch in bp1['boxes']:
        patch.set_facecolor('lightblue')
    for patch in bp2['boxes']:
        patch.set_facecolor('lightcoral')
    
    plt.xticks([1.5, 4.5], ['组1', '组2'])
    plt.title('分组箱线图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

def polar_plots():
    """极坐标图示例"""
    print("=== 极坐标图示例 ===")
    
    plt.figure(figsize=(15, 10))
    
    # 子图1: 基本极坐标图
    plt.subplot(2, 3, 1, projection='polar')
    theta = np.linspace(0, 2*np.pi, 100)
    r = 1 + 0.5 * np.sin(5*theta)
    plt.plot(theta, r)
    plt.title('基本极坐标图', pad=20)
    
    # 子图2: 玫瑰图
    plt.subplot(2, 3, 2, projection='polar')
    theta = np.linspace(0, 2*np.pi, 8, endpoint=False)
    r = [4, 7, 5, 3, 6, 8, 2, 4]
    
    bars = plt.bar(theta, r, width=2*np.pi/len(theta), alpha=0.7)
    for bar, height in zip(bars, r):
        bar.set_facecolor(plt.cm.viridis(height/8))
    plt.title('极坐标柱状图', pad=20)
    
    # 子图3: 螺旋线
    plt.subplot(2, 3, 3, projection='polar')
    theta = np.linspace(0, 4*np.pi, 100)
    r = theta
    plt.plot(theta, r)
    plt.title('螺旋线', pad=20)
    
    # 子图4: 多个同心圆
    plt.subplot(2, 3, 4, projection='polar')
    theta = np.linspace(0, 2*np.pi, 100)
    for i in range(1, 5):
        r = i * np.ones_like(theta)
        plt.plot(theta, r, label=f'r={i}')
    plt.legend(loc='upper left', bbox_to_anchor=(0.1, 1.1))
    plt.title('同心圆', pad=20)
    
    # 子图5: 极坐标散点图
    plt.subplot(2, 3, 5, projection='polar')
    np.random.seed(42)
    n = 100
    theta = np.random.uniform(0, 2*np.pi, n)
    r = np.random.exponential(2, n)
    colors = np.random.rand(n)
    plt.scatter(theta, r, c=colors, alpha=0.7, cmap='hsv')
    plt.title('极坐标散点图', pad=20)
    
    # 子图6: 雷达图
    plt.subplot(2, 3, 6, projection='polar')
    categories = ['能力A', '能力B', '能力C', '能力D', '能力E']
    values = [4, 3, 5, 2, 4]
    
    # 计算角度
    angles = np.linspace(0, 2*np.pi, len(categories), endpoint=False).tolist()
    values += values[:1]  # 闭合图形
    angles += angles[:1]
    
    plt.plot(angles, values, 'o-', linewidth=2, label='个人评分')
    plt.fill(angles, values, alpha=0.25)
    plt.xticks(angles[:-1], categories)
    plt.ylim(0, 5)
    plt.title('能力雷达图', pad=20)
    plt.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))
    
    plt.tight_layout()
    plt.show()

def streamplot_quiver_examples():
    """流线图和矢量场示例"""
    print("=== 流线图和矢量场示例 ===")
    
    plt.figure(figsize=(15, 10))
    
    # 创建网格
    x = np.linspace(-3, 3, 20)
    y = np.linspace(-3, 3, 20)
    X, Y = np.meshgrid(x, y)
    
    # 子图1: 基本矢量场
    plt.subplot(2, 3, 1)
    U = -1 - X**2 + Y
    V = 1 + X - Y**2
    plt.quiver(X, Y, U, V)
    plt.title('基本矢量场')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图2: 彩色矢量场
    plt.subplot(2, 3, 2)
    M = np.sqrt(U**2 + V**2)  # 矢量幅度
    plt.quiver(X, Y, U, V, M, cmap='viridis')
    plt.colorbar(label='矢量幅度')
    plt.title('彩色矢量场')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图3: 流线图
    plt.subplot(2, 3, 3)
    x_stream = np.linspace(-3, 3, 100)
    y_stream = np.linspace(-3, 3, 100)
    X_stream, Y_stream = np.meshgrid(x_stream, y_stream)
    U_stream = -1 - X_stream**2 + Y_stream
    V_stream = 1 + X_stream - Y_stream**2
    
    speed = np.sqrt(U_stream**2 + V_stream**2)
    plt.streamplot(X_stream, Y_stream, U_stream, V_stream, 
                  color=speed, cmap='plasma', density=2)
    plt.colorbar(label='流速')
    plt.title('流线图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图4: 旋涡流场
    plt.subplot(2, 3, 4)
    U_vortex = -Y
    V_vortex = X
    plt.streamplot(X_stream, Y_stream, U_vortex, V_vortex, 
                  color='blue', density=1.5)
    plt.title('旋涡流场')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.axis('equal')
    
    # 子图5: 源流场
    plt.subplot(2, 3, 5)
    U_source = X_stream
    V_source = Y_stream
    plt.streamplot(X_stream, Y_stream, U_source, V_source, 
                  color='red', density=1)
    plt.title('源流场')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.axis('equal')
    
    # 子图6: 组合流场
    plt.subplot(2, 3, 6)
    U_combined = X_stream + 0.5*Y_stream
    V_combined = Y_stream - 0.5*X_stream
    magnitude = np.sqrt(U_combined**2 + V_combined**2)
    
    plt.streamplot(X_stream, Y_stream, U_combined, V_combined, 
                  color=magnitude, cmap='coolwarm', density=2)
    plt.colorbar(label='速度幅度')
    plt.title('组合流场')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    plt.tight_layout()
    plt.show()

def statistical_plots():
    """统计图表示例"""
    print("=== 统计图表示例 ===")
    
    np.random.seed(42)
    
    plt.figure(figsize=(15, 10))
    
    # 子图1: 误差条图
    plt.subplot(2, 3, 1)
    x = np.arange(5)
    y = [20, 35, 30, 35, 27]
    yerr = [2, 3, 4, 1, 2]
    
    plt.errorbar(x, y, yerr=yerr, fmt='o-', capsize=5, capthick=2)
    plt.xticks(x, ['A', 'B', 'C', 'D', 'E'])
    plt.title('误差条图')
    plt.ylabel('值')
    plt.grid(True, alpha=0.3)
    
    # 子图2: 阶梯图
    plt.subplot(2, 3, 2)
    x = np.arange(10)
    y = np.random.randint(1, 10, 10)
    plt.step(x, y, where='mid', linewidth=2)
    plt.fill_between(x, y, step='mid', alpha=0.3)
    plt.title('阶梯图')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.grid(True, alpha=0.3)
    
    # 子图3: 面积图
    plt.subplot(2, 3, 3)
    x = np.linspace(0, 10, 100)
    y1 = np.sin(x)
    y2 = np.cos(x)
    y3 = np.sin(x + np.pi/4)
    
    plt.stackplot(x, y1, y2, y3, labels=['sin(x)', 'cos(x)', 'sin(x+π/4)'],
                 alpha=0.7)
    plt.legend(loc='upper right')
    plt.title('堆叠面积图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    # 子图4: 双轴图
    plt.subplot(2, 3, 4)
    x = np.arange(10)
    y1 = np.random.randint(20, 100, 10)
    y2 = np.random.rand(10) * 5
    
    ax1 = plt.gca()
    line1 = ax1.plot(x, y1, 'b-o', label='数量')
    ax1.set_xlabel('时间')
    ax1.set_ylabel('数量', color='b')
    ax1.tick_params(axis='y', labelcolor='b')
    
    ax2 = ax1.twinx()
    line2 = ax2.plot(x, y2, 'r-s', label='比率')
    ax2.set_ylabel('比率', color='r')
    ax2.tick_params(axis='y', labelcolor='r')
    
    plt.title('双轴图')
    
    # 子图5: 分布对比图
    plt.subplot(2, 3, 5)
    data1 = np.random.normal(0, 1, 1000)
    data2 = np.random.normal(2, 1.5, 1000)
    
    plt.hist(data1, bins=30, alpha=0.5, label='分布1', density=True)
    plt.hist(data2, bins=30, alpha=0.5, label='分布2', density=True)
    
    # 添加密度曲线
    from scipy import stats
    x_range = np.linspace(-4, 6, 100)
    plt.plot(x_range, stats.norm.pdf(x_range, 0, 1), 'b-', label='理论1')
    plt.plot(x_range, stats.norm.pdf(x_range, 2, 1.5), 'r-', label='理论2')
    
    plt.legend()
    plt.title('分布对比图')
    plt.xlabel('值')
    plt.ylabel('密度')
    
    # 子图6: 置信区间图
    plt.subplot(2, 3, 6)
    x = np.linspace(0, 10, 50)
    y = 2 * x + 1 + np.random.normal(0, 2, 50)
    
    # 线性回归
    z = np.polyfit(x, y, 1)
    p = np.poly1d(z)
    plt.plot(x, y, 'o', alpha=0.5, label='数据点')
    plt.plot(x, p(x), 'r-', linewidth=2, label='拟合线')
    
    # 置信区间
    residuals = y - p(x)
    std_residuals = np.std(residuals)
    plt.fill_between(x, p(x) - 2*std_residuals, p(x) + 2*std_residuals, 
                    alpha=0.2, label='95%置信区间')
    
    plt.legend()
    plt.title('置信区间图')
    plt.xlabel('X')
    plt.ylabel('Y')
    
    plt.tight_layout()
    plt.show()

def main():
    """主函数，运行所有高级图表示例"""
    print("Matplotlib 高级图表类型演示")
    print("=" * 50)
    
    contour_plots()
    heatmap_examples()
    boxplot_violin_examples()
    polar_plots()
    streamplot_quiver_examples()
    statistical_plots()
    
    print("\n高级图表演示完成！")
    print("这些图表类型适用于：")
    print("- 科学数据可视化")
    print("- 统计分析结果展示")
    print("- 工程技术图表")
    print("- 多维数据展示")

if __name__ == "__main__":
    main() 